home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 27 / CU Amiga Magazine's Super CD-ROM 27 (1998)(EMAP Images)(GB)[!][issue 1998-10].iso / CUCD / PowerPC / vbcc / machines / amigawos / libsrc / fd2lib / fd2libWOS.c next >
C/C++ Source or Header  |  1998-08-02  |  23KB  |  777 lines

  1. /*
  2. **  fd2lib (M68k) by Volker Barthelmann
  3. **  rework 09/96 by Johnny Teveßen <j.tevessen@line.org>
  4. **  PPC/SVR4 version by Volker Barthelmann in 12/97
  5. **======================================================================
  6. **  PowerPC/WarpOS version (fd2libWOS) and complete rework by
  7. **  Frank Wille <frank@phoenix.owl.de> in 1998
  8. **======================================================================
  9. **  fd2libWOS is freeware and part of the portable and retargetable
  10. **  ANSI C compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
  11. **  fd2libWOS may be freely redistributed as long as no modifications
  12. **  are made and nothing is charged for it. Non-commercial usage is
  13. **  allowed without restrictions.
  14. **======================================================================
  15. **
  16. **  v1.1  08-Jul-98 phx
  17. **        Deleted definition of @_-symbols. vlink will create them on demand.
  18. **        Renamed into fd2libWOS.
  19. **        vbcc-WarpOS is ready for beta stage.
  20. **  V1.0  16-Jun-98 phx
  21. **        vbccppc support direct TOC access. DIRECT_TOC_ACCES = 1.
  22. **  V0.9  02-Jun-98 phx
  23. **        Most AmigaOS prototypes for vararg functions force the first
  24. **        vararg into a register. A table contains those functions,
  25. **        which has a 'correct' prototype:
  26. **        EasyRequest,BuildEasyRequest,FWritef,FPrintf,Printf
  27. **  V0.8  01-Jun-98 phx
  28. **        Complete rework.
  29. **        The new keyword '##abi' is supported, to be able to generate
  30. **        stub routines for M68k *and* PPC functions.
  31. **  V0.7  30-May-98 phx
  32. **        Fixed stack frame offsets, when accessing argumentes on
  33. **        the stack.
  34. **  V0.5  21-Apr-98 phx
  35. **        Wrongs offsets.
  36. **  V0.3  10-Mar-98 phx
  37. **        Prefix for TOC symbols is "@_" and not "@".
  38. **  V0.2  03-Mar-98 phx
  39. **        copied fd2libppc.c
  40. */
  41.  
  42. #define NDEBUG
  43.  
  44. /* only non-public (alpha) vbcc-wos releases had a zero here, */
  45. /* it's set to 1 since beta stage */
  46. #define DIRECT_TOC_ACCESS 1
  47.  
  48. #include <stdio.h>
  49. #include <stdlib.h>
  50. #include <string.h>
  51. #include <ctype.h>
  52. #include <stdarg.h>
  53.  
  54. #define VERSION 1
  55. #define REVISION 1
  56. /* AmigaOS version string. Doesn't hurt... */
  57. const char VersTag[] = "\0$VER: fd2lib WOS 1.1 (08.07.98)";
  58.  
  59. #define MAXLINELEN      1000
  60. #define BUFFEREDLEN     16384   /* 1024 is standard */
  61.  
  62. /* FD-file processing modes */
  63. #define SMALLDATA        1      /* Small data access (currently no effect) */
  64. #define VARGSLOGIC       2      /* detect ...A and ...TagList functions */
  65. #define DEBUG            4      /* Debugging mode */
  66.  
  67. #define NUMREGS         16      /* number of M68k register in FD files */
  68. static const char *regnames[NUMREGS] =
  69. {
  70.   "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
  71.   "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7"
  72. };
  73.  
  74. enum
  75. {
  76.   A0=0, A1, A2, A3, A4, A5, A6, A7,
  77.   D0  , D1, D2, D3, D4, D5, D6, D7
  78. };
  79.  
  80. /* ABIs */
  81. #define ABI_68k         0
  82. #define ABI_68k_NAME    "M68k"
  83. #define ABI_PPC         1
  84. #define ABI_PPC_NAME    "PPC"
  85.  
  86. typedef short BOOL;
  87.  
  88. #ifndef   TRUE
  89. #  define TRUE  1
  90. #  define FALSE 0
  91. #endif
  92.  
  93. #ifndef   NULL
  94. #  define NULL ((void *)0L)
  95. #endif
  96.  
  97.  
  98. static const char *varargs[] =
  99. {
  100. #include "vargs.h"
  101.   NULL, NULL
  102. };
  103.  
  104.  
  105. /* these (few) OS functions have correct varargs prototypes */
  106. static const char *std_vargs[] =
  107. {
  108. #include "stdvargs.h"
  109.   NULL
  110. };
  111.  
  112.  
  113.  
  114.  
  115. static void ExitFailure(const char *cause,...)
  116. {
  117.   va_list vl;
  118.  
  119.   va_start(vl,cause);
  120.   vfprintf(stderr,cause,vl);
  121.   va_end(vl);
  122.   exit(EXIT_FAILURE);
  123. }
  124.  
  125.  
  126. static void check(const char *ptr)
  127. {
  128.   if(!*ptr)
  129.     ExitFailure("Unexpected EOL\n");
  130. }
  131.  
  132.  
  133. static void warnhim(int linenr, const char *format, ...)
  134. {
  135.   char linebuf[250];
  136.   va_list vl;
  137.  
  138.   va_start(vl,format);
  139.   vsprintf(linebuf, format, vl);
  140.   va_end(vl);
  141.  
  142.   fprintf(stderr, "Warning line %d: %s\n", linenr, linebuf);
  143. }
  144.  
  145.  
  146. static FILE * OpenLVO(const char *name, const char *outdir,
  147.                       const char *outform)
  148. /* The LVO file is currently genereted for an M68k assembler. */
  149. /* It will get the extension .asm, instead of .s */
  150. {
  151.   FILE *lvos;
  152.   char lvoname[MAXLINELEN];
  153.  
  154.   strcpy(lvoname, outdir);
  155.  
  156.   if(name) {
  157.     char *k = (char *)name, *p;
  158.     int lvonamlen;
  159.  
  160.     if((p = strrchr(k, '/')) != NULL) k = p + 1;
  161.     if((p = strrchr(k, ':')) != NULL) k = p + 1;
  162.  
  163.     strcat(lvoname, k);
  164.  
  165.     lvonamlen = strlen(lvoname);
  166.  
  167.     if((lvonamlen > 7) && !strcmp(lvoname+lvonamlen-7, "_lib.fd"))
  168.       lvoname[lvonamlen-7] = '\0';
  169.     else if((lvonamlen > 3) && !strcmp(lvoname+lvonamlen-3, ".fd"))
  170.       lvoname[lvonamlen-3] = '\0';
  171.  
  172.     strcat(lvoname, "_lvo.asm");
  173.   }
  174.   else
  175.     strcat(lvoname, "fd_lvo.asm");
  176.  
  177.   printf(outform, lvoname, lvoname, lvoname);
  178.  
  179.   lvos = fopen(lvoname, "w");
  180.   fprintf(lvos,"\tsection\t.data,data\n\n");  /* Amiga68k assembler syntax */
  181.   return(lvos);
  182. }
  183.  
  184.  
  185. static void ProcessFD(const char *name, int mode, const char *outdir,
  186.                       const char *outform)
  187. {
  188.   FILE *fh, *lvos;
  189.   FILE *out;
  190.   int offset = 0, i, j, count, savecount;
  191.   char function[80], tmpfuncnam[80], ff[MAXLINELEN+8], base[50];
  192.   char line[MAXLINELEN];
  193.   register char *p;
  194.   char *functionp;
  195.   int reg[NUMREGS], loops, linenr = 0, stksize, abi = ABI_68k;
  196.   BOOL first_va_in_reg, public = -1;
  197.   /*
  198.   **  "-1" is the initial value for "public". It means:
  199.   **  no statement yet.
  200.   */
  201.  
  202.   *function = *base = *line = '\0';
  203.  
  204.   /* open FD file */
  205.   if (name) {
  206.     if (!(fh = fopen(name, "r")))
  207.       ExitFailure("Could not open `%s'\n", name);
  208.   }
  209.   else
  210.     fh = stdin;
  211.   setvbuf(fh, NULL, _IOFBF, BUFFEREDLEN);             /* maybe _IOLBF? */
  212.  
  213.   /* open LVO file */
  214.   if (!(lvos = OpenLVO(name, outdir, outform)))
  215.     ExitFailure("Could not create lvo file\n");
  216.   setvbuf(lvos, NULL, _IOFBF, BUFFEREDLEN);
  217.  
  218.   for(;;)
  219.   {
  220.     char *k;
  221.  
  222.     if (!fgets(line, MAXLINELEN-1, fh))
  223.       ExitFailure("Unexpected EOF\n");
  224.  
  225.     linenr ++;
  226.     if ((*line == '*') || !*line)
  227.       continue;
  228.  
  229.     switch(*line + line[2]) {
  230.       case ('#'+'a'):
  231.         if (!strncmp(line, "##abi", 5)) {               /* ##abi */
  232.           p = line+5;
  233.           while (isspace((unsigned)*p)) p++;
  234.           if (!strncmp(p, ABI_68k_NAME, sizeof(ABI_68k_NAME)-1)) {
  235.             abi = ABI_68k;
  236.             if(mode & DEBUG)
  237.               printf("ABI set to M68k\n");
  238.           }
  239.           else if (!strncmp(p, ABI_PPC_NAME, sizeof(ABI_PPC_NAME)-1)) {
  240.             abi = ABI_PPC;
  241.             if(mode & DEBUG)
  242.               printf("ABI set to PPC (WarpOS)\n");
  243.           }
  244.           else
  245.             warnhim(linenr, "Unknown ##abi specification ignored!");
  246.           continue;
  247.         }
  248.         break;
  249.  
  250.       case ('#'+'b'):
  251.         if (!strncmp(line, "##base", 6)) {              /* ##base */
  252.           if (*base)
  253.             warnhim(linenr, "##base detected more than once!");
  254.           p = line+6;
  255.           while (isspace((unsigned)*p)) p++;
  256.           k = base;
  257.           while (isgraph((unsigned)*p)) *k++ = *p++;
  258.           *k = '\0';
  259.           if(mode & DEBUG)
  260.             printf("Base set to `%s'\n", base);
  261.           continue;
  262.         }
  263.  
  264.         if (!strncmp(line, "##bias", 6)) {               /* ##bias */
  265.           p = line+6;
  266.           while (isspace((unsigned)*p)) p++;
  267.           sscanf(p, "%i", &offset);
  268.           if (mode & DEBUG)
  269.             printf("Bias set to -%d\n", offset);
  270.           continue;
  271.         }
  272.         break;
  273.  
  274.       case ('#'+'p'):
  275.         if (!strncmp(line, "##public", 8)) {            /* ##public */
  276.           if (public == TRUE)
  277.             warnhim(linenr, "##public after ##public detected!");
  278.           else
  279.             public = TRUE;
  280.           if (mode & DEBUG)
  281.             printf("Turned on public mode at bias -%d\n", offset);
  282.           continue;
  283.         }
  284.  
  285.         if (!strncmp(line, "##private", 9)) {           /* ##private */
  286.           if (public == FALSE)
  287.             warnhim(linenr, "##private after ##private detected!");
  288.           else
  289.             public = FALSE;
  290.           if (mode & DEBUG)
  291.             printf("Turned off public mode at bias -%d\n", offset);
  292.           continue;
  293.         }
  294.         break;
  295.  
  296.       case ('#'+'e'):
  297.         if(!strncmp(line, "##end", 5))                  /* ##end */
  298.           return;
  299.         break;
  300.     }
  301.  
  302.     if (*line == '#') {
  303.       warnhim(linenr, "Unknown directive: `%s'!", line);
  304.       continue;
  305.     }
  306.  
  307.     if (public == FALSE)
  308.     {
  309.       offset += 6;
  310.       continue;
  311.     }
  312.     if (public == -1) {
  313.       warnhim(linenr, "Neither ##public nor ##private specified yet. "
  314.                       "Assuming ##public.");
  315.       public = TRUE;
  316.     }
  317.     functionp = function;
  318.  
  319.     /* Stub Generation Loops */
  320.     for (loops=0; loops<=1; loops++) {
  321.       char *p = line;
  322.       char *k = functionp;
  323.  
  324.       while (isspace((unsigned)*p)) p++;
  325.  
  326.       if (loops == 0) {
  327.         /* get function name */
  328.         while ((*p != '(') && *p)
  329.           *k++ = *p++;
  330.         check(p);
  331.         *k = '\0';
  332.  
  333.         /* create entry for function name in _LVOxxx file */
  334.         fprintf(lvos, "_LVO%s\tequ\t-%d\n"
  335.                       "\txdef\t_LVO%s\n",
  336.                       functionp, offset, functionp);
  337.       }
  338.       else {
  339.         /* skip function name */
  340.         while ((*p != '(') && *p)
  341.           p++;
  342.         check(p);
  343.       }
  344.  
  345.       if(mode & DEBUG)
  346.         printf("function=%s, loops=%d\n", functionp, loops);
  347.  
  348.       /* Open function stub source file */
  349.       sprintf(ff, "%s%s.s", outdir, functionp);
  350.       printf(outform, ff, ff, ff);
  351.       out = fopen(ff, "w");
  352.       if(!out)
  353.         ExitFailure("Could not create <%s>\n", functionp);
  354.       setvbuf(out, NULL, _IOFBF, BUFFEREDLEN);
  355.  
  356.       switch (abi) {
  357.  
  358.         case ABI_68k:
  359.  
  360.           /* Write assembler headers */
  361. #if DIRECT_TOC_ACCESS
  362.           fprintf(out,"\t.file\t\"%s.s\"\n\t.extern _PowerPCBase\n"
  363.                   "\t.extern %s\n\t.global _%s\n",
  364.                   functionp,base,functionp);
  365.  
  366. #else /* as long as vbcc doesn't support direct TOC-access... */
  367.           fprintf(out,"\t.file\t\"%s.s\"\n\t.extern _PowerPCBase\n"
  368.                   "\t.extern @_%s\n\t.global _%s\n",
  369.                   functionp,base,functionp);
  370. #endif
  371.  
  372.           fprintf(out,"\t.text\n\t.align\t3\n_%s:\n",functionp);
  373.  
  374.           /* Set all registers to 'unused' */
  375.           for(i=0; i<NUMREGS; reg[i++]=0)
  376.  
  377.           /* Skip argument names */
  378.           while ((*p!=')') && *p) p++;
  379.           check(p);
  380.           p++;
  381.  
  382.           /* Search for beginning of register list */
  383.           while ((*p!='(') && *p) p++;
  384.           check(p);
  385.           p++;
  386.  
  387.           /* Scan register list */
  388.           count = savecount = 0;
  389.  
  390.           while ((*p!=')') && *p) {
  391.             /* Check whether register description is valid */
  392.             if ((!((*p=='a') || (*p=='A') || (*p=='d') || (*p=='D'))) ||
  393.                  !((p[1]>='0') && (p[1]<='7')))
  394.               ExitFailure("Bad register description '%c%c'\n",p[0],p[1]);
  395.  
  396.             /* Convert description to internal enum format */
  397.             if ((*p=='a') || (*p=='A'))
  398.               j = p[1] -  '0';
  399.             else
  400.               j = p[1] - ('0'-8);
  401.  
  402.             /* Mark register as used and save its argument counter */
  403.             reg[j] = ++count;
  404.  
  405.             /* Increase counter if register has to be saved */
  406.             if (!(j==A0 || j==A1 || j==A6 || j==D0 || j==D1))
  407.               savecount ++;
  408.  
  409.             /* Search for next register */
  410.             p += 2;
  411.             while (isspace((unsigned)*p) && *p) p++;
  412.             if ((*p == '/') || (*p==',')) p++;
  413.             else
  414.               if (*p != ')')
  415.                 ExitFailure("Parse error - ')' expected\n");
  416.             while (isspace((unsigned)*p) && *p) p++;
  417.             check(p);
  418.           }
  419.  
  420.           fprintf(out,"\tmflr\tr0\n\tstw\tr0,8(r1)\n"
  421.                       "\tstwu\tr1,-0xb0(r1)\n");
  422.  
  423.           /* clear PP_Flags, PP_Stack and PP_StackSize */
  424.           fprintf(out,"\tli\tr11,0\n\tstw\tr11,0x28(r1)\n"
  425.                   "\tstw\tr11,0x2c(r1)\n\tstw\tr11,0x30(r1)\n");
  426.  
  427.           /* set library base and offset */
  428. #if DIRECT_TOC_ACCESS
  429.           fprintf(out,"\tlwz\tr0,%s(r2)\n\tli\tr11,-%d\n"
  430.                   "\tstw\tr0,0x20(r1)\n\tstw\tr11,0x24(r1)\n"
  431.                   "\tstw\tr0,0x6c(r1)\n",base,offset);
  432.  
  433. #else /* as long as vbcc doesn't support direct TOC-access... */
  434.           fprintf(out,"\tlwz\tr11,@_%s(r2)\n\tlwz\tr0,0(r11)\n\tli\tr11,-%d\n"
  435.                   "\tstw\tr0,0x20(r1)\n\tstw\tr11,0x24(r1)\n"
  436.                   "\tstw\tr0,0x6c(r1)\n",base,offset);
  437. #endif
  438.  
  439.           for (i=0; i<NUMREGS; i++) { /* Registers */
  440.             if (reg[i]) {
  441.               if (!loops || reg[i]<count) {
  442.                 if (reg[i] <= 8)
  443.                   fprintf(out,"\tstw\tr%d,",reg[i]+2);
  444.                 else
  445.                   fprintf(out,"\tlwz\tr11,%d(r1)\n"
  446.                           "\tstw\tr11,",reg[i]*4+196);
  447.               }
  448.               else{
  449.                 /* VarArgs */
  450.                 if (loops && first_va_in_reg) {
  451.                   /* copy register into varargs stack */
  452.                   fprintf(out,"\tstw\tr%d,%d(r1)\n",
  453.                           reg[i]+2,0xc4+count*4);
  454.                 }
  455.                 fprintf(out,"\taddi\tr11,r1,%d\n\tstw\tr11,",
  456.                         0xc4+count*4);
  457.               }
  458.               if (i <= 7)
  459.                 fprintf(out,"%d(r1)\n",0x54+4*i);
  460.               else
  461.                 fprintf(out,"%d(r1)\n",0x34+4*(i-8));
  462.             }
  463.           } /* for i */
  464.  
  465.           /* Now place the real function call */
  466.           fprintf(out,"\tlwz\tr3,_PowerPCBase(r2)\n\taddi\tr4,r1,0x20\n"
  467.                   "\tlwz\tr0,-298(r3)\n\tmtlr\tr0\n\tblrl\n"
  468.                   "\tlwz\tr3,0x34(r1)\n");
  469.           fprintf(out,"\taddi\tr1,r1,0xb0\n\tlwz\tr0,8(r1)\n"
  470.                   "\tmtlr\tr0\n\tblr\n"
  471.                   "\t.type\t_%s,@function\n"
  472.                   "\t.size\t_%s,$-_%s\n\n",
  473.                   functionp,functionp,functionp);
  474.           fclose(out);
  475.           break;
  476.  
  477.         case ABI_PPC:
  478.  
  479.           /* Write assembler headers */
  480.           fprintf(out,"\t.file\t\"%s.s\"\n\t.text\n"
  481. #if DIRECT_TOC_ACCESS
  482.                   "\t.extern %s\n\n"
  483. #else
  484.                   "\t.extern @_%s\n\n"
  485. #endif
  486.                   "\t.align\t3\n\t.globl\t_%s\n_%s:\n",
  487.                   functionp,base,functionp,functionp);
  488.  
  489.           /* Search for beginning of argument list */
  490.           while (*p!='(' && *p) p++;
  491.           check(p);
  492.           p++;
  493.  
  494.           /* determine the number of arguments */
  495.           count = 0;
  496.           for (;;) {
  497.             while (*p!=')' && isspace((unsigned)*p) && *p)
  498.               ++p;
  499.             check(p);
  500.             if (*p == ')')
  501.               break;
  502.             count++;
  503.             while (*p!=')' && *p!=',' && *p)
  504.               ++p;
  505.             check(p);
  506.             if (*p++ == ')')
  507.               break;
  508.           }
  509.           if (mode & DEBUG)
  510.             printf("PPC function %s has %d arguments.\n",functionp,count);
  511.           if (count > 26)
  512.             ExitFailure("PPC function %s exceeds the current limitation"
  513.                         "of 26 arguments by %d!",functionp,count-26);
  514.  
  515.           /* init stack frame */
  516.           stksize = (count<8) ? 32 : ((56+(count-7)*8+15)&~15);
  517.           fprintf(out,"\tmflr\tr0\n\tstw\tr0,8(r1)\n"
  518.                       "\tstwu\tr1,-%d(r1)\n",stksize);
  519.  
  520.           if (count > 7) {
  521.             /* extra arguments must be passed on the stack */
  522.             if (count == 8) {
  523.               /* special case: move 8th argument into stack frame */
  524.               if (loops)  /* varargs? */
  525.                 fprintf(out,"\taddi\tr10,r1,%d\n",stksize+20+count*4);
  526.               fprintf(out,"\tstw\tr10,56(r1)\n");
  527.             }
  528.             else {
  529.               int firstreg = 32-(count-7);
  530.  
  531.               fprintf(out,"\tstmw\tr%d,%d(r1)\n"
  532.                       "\tmr\tr%d,r10\n"
  533.                       "\tlmw\tr%d,%d(r1)\n",
  534.                       firstreg,56+(count-7)*4,firstreg,
  535.                       firstreg+1,stksize+56);
  536.               if (loops)  /* varargs? */
  537.                 fprintf(out,"\taddi\tr31,r1,%d\n",stksize+20+count*4);
  538.               fprintf(out,"\tstmw\tr%d,56(r1)\n",firstreg);
  539.             }
  540.           }
  541.           else if (loops) {  /* pass varargs pointer in a register? */
  542.             fprintf(out,"\taddi\tr%d,r1,%d\n",count+3,stksize+20+count*4);
  543.             /* ATTENTION: count will be modified and must not be */
  544.             /*            used for calculations after this point! */
  545.             --count;
  546.           }
  547.  
  548.           /* shift all arguments into their following register */
  549.           for (i=(count<8)?count:7; i>0; i--)
  550.             fprintf(out,"\tmr\tr%d,r%d\n",3+i,2+i);
  551.  
  552.           /* load library base and LVO, then call LVO via LR */
  553.           fprintf(out,
  554. #if DIRECT_TOC_ACCESS
  555.                   "\tlwz\tr3,%s(r2)\n"
  556. #else
  557.                   "\tlwz\tr3,@_%s(r2)\n\tlwz\tr3,0(r3)\n"
  558. #endif
  559.                   "\tlwz\tr0,-%d(r3)\n"
  560.                   "\tmtlr\tr0\n"
  561.                   "\tblrl\n",base,offset-2);
  562.  
  563.           /* cleanup stack frame and return */
  564.           if (count > 8)
  565.             fprintf(out,"\tlmw\tr%d,%d(r1)\n",  /* restore saved regs */
  566.                     32-(count-7),56+(count-7)*4);
  567.           fprintf(out,"\taddi\tr1,r1,%d\n"
  568.                   "\tlwz\tr0,8(r1)\n\tmtlr\tr0\n\tblr\n"
  569.                   "\t.type\t_%s,@function\n"
  570.                   "\t.size\t_%s,$-_%s\n\n",
  571.                   stksize,functionp,functionp,functionp);
  572.  
  573.           fclose(out);
  574.           break;
  575.  
  576.       } /* switch */
  577.  
  578.       if (loops > 0) break;
  579.  
  580.       p = (char *)*varargs;
  581.       loops = 3;
  582.       if (mode & DEBUG)
  583.         printf("Searching function `%s' in vargs table...\n", functionp);
  584.  
  585.       if (p != NULL) {
  586.         if (mode & VARGSLOGIC) {
  587.           int fnlen = strlen(functionp);
  588.  
  589.           if ((fnlen > 7) && (!strcmp(functionp+fnlen-7, "TagList"))) {
  590.             /* xxxTagList function found. Make xxxTags of it */
  591.             strncpy(tmpfuncnam, functionp, fnlen-4);
  592.             strcpy(tmpfuncnam+fnlen-4, "s");
  593.             functionp = tmpfuncnam;
  594.             loops = 0;
  595.           }
  596.  
  597.           else if ((fnlen > 1) && ((functionp[fnlen-1] == 'A') &&
  598.                    (functionp[fnlen-2] >= 'a') && 
  599.                    (functionp[fnlen-2] <= 'z'))) {
  600.             /*  Not that smart recognition... But you probably
  601.             **  don't want to have a function CreateDA() varargs,
  602.             **  want you?
  603.             **
  604.             **  Recognized are functions that end with 'A' and that
  605.             **  have a lowercase letter before that.
  606.             */
  607.             strcpy(tmpfuncnam, functionp);
  608.             tmpfuncnam[fnlen-1] = '\0';
  609.             functionp = tmpfuncnam;
  610.             loops = 0;
  611.           }
  612.  
  613.           if (!loops && (mode&DEBUG))
  614.             puts("Found via internal logic!");
  615.         }
  616.  
  617.         if (loops) {
  618.           for(i=0; p!=NULL; i+=2) {
  619.             if (!strcmp(p, functionp)) {
  620.               char **stdva = (char **)std_vargs;
  621.  
  622.               if (mode & DEBUG)
  623.                 puts("Found!");
  624.               functionp = (char *)varargs[i-1];
  625.               loops = 0;
  626.  
  627.               /* The AmigaOS clib/#?.h header files unfortunately */
  628.               /* declare most vararg functions with the first vararg */
  629.               /* appearing in the argument list. */
  630.               /* vbcc's PowerOpen code generator will pass the first */
  631.               /* vararg in a register then. :(  */
  632.               first_va_in_reg = TRUE;
  633.  
  634.               /* uses correct prototype? */
  635.               while (*stdva) {
  636.                 if (!strcmp(*stdva,functionp)) {
  637.                   if (mode & DEBUG)
  638.                     printf("%s() assumed to use correct prototype.\n",
  639.                            functionp);
  640.                   first_va_in_reg = FALSE;
  641.                   break;
  642.                 }
  643.                 stdva++;
  644.               }
  645.               break;
  646.             }
  647.             p = (char *)varargs[i];
  648.           }
  649.         }
  650.       }
  651.     }
  652.  
  653.     offset += 6;
  654.   } /* for(;;) */
  655.  
  656.   if(name)
  657.     fclose(fh);
  658.   fclose(lvos);
  659. }
  660.  
  661.  
  662. static void fillpath(char *dirpath)
  663. /*  Append '/' to path if needed */
  664. {
  665.   int sl = strlen(dirpath);
  666.  
  667.   switch(dirpath[sl-1]) {
  668.     case ':':
  669.     case '/':
  670.       break;
  671.     default:
  672.       strcpy(dirpath+sl, "/");
  673.       break;
  674.   }
  675. }
  676.  
  677.  
  678. static void Usage(const char *myname)
  679. /*  Show program usage */
  680. {
  681.   printf("fd2lib WarpOS V%d.%d\n"
  682.          "(c)1996-98 by Frank Wille, Volker Barthelmann, Johnny Teveßen\n"
  683.          "\n"
  684.          "  -- Caution: Needs ~5000 byte stack! --\n"
  685.          "\n"
  686.          "Usage: %s [-sd] [-nv] [-o <dir>] [-of <format>] "
  687.          "[-d] [-?|--help] [files/pattern]\n"
  688.          "\nOptions:\n"
  689.          "-sd    Use small data model (currently not supported)\n"
  690.          "-nv    No varargs logic - ...A and ...TagList will not be detected\n"
  691.          "-o     Specify directory to store source files in\n"
  692.          "-of    C printf style output format to generate compiling\n"
  693.          "       script. Three `%%s' are replaced with output file name\n"
  694.          "-d     Turn on debugging/verbose mode\n"
  695.          "-?     Show help/version and quit\n"
  696.          "files  FD files to convert, defaults to stdin\n"
  697.          "\n"
  698.          "Commandline is parsed left-to-right. Specifying\n"
  699.          "\"alib_lib.fd -sd blib_lib.fd\" will result in alib\n"
  700.          "getting large data model.\n",VERSION,REVISION,myname);
  701.   exit(0);
  702. }
  703.  
  704.  
  705. int main(int argc, char *argv[])
  706. {
  707.   int erg       = 0  /* EXIT_FAILURE */;
  708.   int mode      = VARGSLOGIC;
  709.   int filesdone = 0;
  710.  
  711.   char outdir[80] = "", outform[250] = "";
  712.  
  713.   if(argc > 1) {
  714.     int i;
  715.  
  716.     for(i=1; i<argc; i++) {
  717.       if(argv[i][0] == '-') {
  718.         /* Parse option */
  719.  
  720.         if( !strcmp(argv[i], "-sd")) mode |=  SMALLDATA;
  721.         else if( !strcmp(argv[i], "-nv")) mode &= ~VARGSLOGIC;
  722.         else if( !strcmp(argv[i], "-o" )) {
  723.           if(i < (argc-1)) {
  724.             i ++;
  725.             if(strlen(argv[i]) < sizeof(outdir)) {
  726.               strcpy  (outdir, argv[i]);
  727.               fillpath(outdir);
  728.             }
  729.             else {
  730.               fprintf(stderr, "Path too long. Maximum is %lu characters. Ignored.\n", (unsigned long)sizeof(outdir));
  731.             }
  732.           }
  733.           else {
  734.             fputs("No path specified after `-o'!\n", stderr);
  735.           }
  736.         }
  737.         else if( !strcmp(argv[i], "-of")) {
  738.           if(i < (argc-1)) {
  739.             i ++;
  740.             if(strlen(argv[i]) < sizeof(outform)) {
  741.               strcpy(outform, argv[i]);
  742.               strcat(outform, "\n"   );
  743.             }
  744.             else {
  745.               fprintf(stderr, "Format too long. Maximum is %lu characters. Ignored.\n", (unsigned long)sizeof(outform));
  746.             }
  747.           }
  748.           else {
  749.             fputs("No format specified after `-of'!\n", stderr);
  750.           }
  751.         }
  752.         else if( !strcmp(argv[i], "-d" )) mode |=  DEBUG;
  753.         else if((!strcmp(argv[i], "-?" )) ||
  754.                 (!strcmp(argv[i], "--help"))) Usage(*argv);
  755.         else {
  756.           fprintf(stderr, "Unknown option `%s'\n\n", argv[i]);
  757.           Usage(*argv);
  758.         }
  759.       }
  760.       else {
  761.         /* Process file */
  762.         if(argv[i][0] == '?')
  763.           Usage(*argv);
  764.         else {
  765.           ProcessFD(argv[i], mode, outdir, outform);
  766.           filesdone ++;
  767.         }
  768.       }
  769.     }
  770.   }
  771.  
  772.   if(!filesdone)
  773.     ProcessFD(NULL, mode, outdir, outform);
  774.  
  775.   return(erg);
  776. }
  777.